﻿#include "FormBase64.h"
#include "FuncDefine.h"

#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGridLayout>

#include <QDebug>
#include <QApplication>
#include <QCryptographicHash>
#include <QClipboard>

#include "design/styleDefine.h"
#include "design/CustomMessageDialog.h"
#include "tools/base64.h"
#include "tools/util.h"

std::pair<QLabel*, QLabel*> addItem2GridLayout(QWidget* parent, QGridLayout* pLayout, QString strTitle, uint nIndex)
{
    QLabel *pTitle = new QLabel(parent);
    QLabel *pInfo = new QLabel(parent);
    pTitle->setText(strTitle);
    pTitle->setFixedSize(200, 25);
    pTitle->setFont(gFontConsolas);
    pInfo->setFont(gFontConsolas);
    pLayout->addWidget(pTitle, nIndex, 0);
    pLayout->addWidget(pInfo, nIndex, 1);

    if(0 == nIndex % 2)
    {
        pTitle->setStyleSheet(g_label1);
        pInfo->setStyleSheet(g_label1);
    }
    else
    {
        pTitle->setStyleSheet(g_label2);
        pInfo->setStyleSheet(g_label2);
    }

    std::pair<QLabel*, QLabel*> nRet = std::make_pair(pTitle, pInfo);
    return nRet;
}

FluButton* addPtn2GridLayout(QWidget *parent, QGridLayout *pLayout, QString strTitle, uint nIndex)
{
    FluButton* pBtn = new FluButton(parent);
    pBtn->setText(strTitle);
    pBtn->setMaximumWidth(150);
    pLayout->addWidget(pBtn, nIndex, 2);
    return pBtn;
}

QString getSrcMD5Value(QString strSrc)
{
    // 创建一个QCryptographicHash实例
    QCryptographicHash hash(QCryptographicHash::Md5);

    // 添加要计算哈希值的数据
    hash.addData(strSrc.toUtf8());

    // 获取计算出的哈希值
    QByteArray hashResult = hash.result();

    // 将哈希值转换为十六进制字符串
    QString hashString = QString(hashResult.toHex());

    return hashString;
}

FormBase64Proc::FormBase64Proc(QWidget* parent)
    : QFrame(parent)
    , m_pTextEdit(nullptr)
    , m_pRead(nullptr)
    , m_pMDValue(nullptr)
    , m_bMD5Value(false)
{
    m_strLastData.clear();
    this->setStyleSheet(PAGE_COMMON_SELECTED_COLOUR);

    QVBoxLayout* pLayout = new QVBoxLayout;
    pLayout->setSpacing(WIDGET_SPACINGS_LEN);
    pLayout->setContentsMargins(5, 5, 5, 5);
    setLayout(pLayout);

    m_pTextEdit = new CustomTextEdit();
    pLayout->addWidget(m_pTextEdit);
    m_pTextEdit->setPlaceholderText(QStringLiteral("输入区域可粘贴待编解码文本，或将文件拖拽到输入区域中自动识别"));

    QHBoxLayout* pTools = new QHBoxLayout;
    pLayout->addLayout(pTools);
    pTools->setContentsMargins(WIDGET_CONTENTS_MARGINS, 0, WIDGET_CONTENTS_MARGINS, 0);

    FluButton* pDecode = new FluButton(this);
    FluButton* pEncode = new FluButton(this);
    pTools->addWidget(pDecode);
    pTools->addWidget(pEncode);
    pTools->addStretch();

    pDecode->setText("解 码");
    pEncode->setText("编 码");
    connect(pDecode, SIGNAL(clicked()), this, SLOT(slt_decode()));
    connect(pEncode, SIGNAL(clicked()), this, SLOT(slt_encode()));

    // 设置展示信息控件
    QGridLayout* pShowTable = new QGridLayout;
    pLayout->addLayout(pShowTable);
    pShowTable->setSpacing(WIDGET_SPACINGS_LEN);
    pShowTable->setContentsMargins(WIDGET_CONTENTS_MARGINS, WIDGET_CONTENTS_MARGINS, WIDGET_CONTENTS_MARGINS, WIDGET_CONTENTS_MARGINS);
    m_pSrcFileType = addItem2GridLayout(this, pShowTable, "  原始数据类型", 0);
    m_pSrcLenInfo = addItem2GridLayout(this, pShowTable, "  原始数据长度", 1);
    m_pDetLenInfo = addItem2GridLayout(this, pShowTable, "  结果数据长度", 2);
    m_pSrcMD5Info = addItem2GridLayout(this, pShowTable, "  原始数据MD5值", 3);
    m_pDetMD5Info = addItem2GridLayout(this, pShowTable, "  结果数据MD5值", 4);
    m_pSaveInfo = addItem2GridLayout(this, pShowTable, "  结果保存为", 5);
    m_pSaveInfo.first->hide();
    m_pSaveInfo.second->hide();

    m_pRead = addPtn2GridLayout(this, pShowTable, "展示结果", 0);
    connect(m_pRead, SIGNAL(clicked()), this, SLOT(slt_read()));

    FluButton* pClear = addPtn2GridLayout(this, pShowTable, "清空内容", 1);
    connect(pClear, SIGNAL(clicked()), this, SLOT(slt_clear()));

    FluButton* pCopy2Clipboard = addPtn2GridLayout(this, pShowTable, "拷贝到剪切板", 2);
    connect(pCopy2Clipboard, SIGNAL(clicked()), this, SLOT(slt_copy2Clipboard()));

    m_pMDValue = addPtn2GridLayout(this, pShowTable, "MD5已关闭", 3);
    connect(m_pMDValue, SIGNAL(clicked()), this, SLOT(slt_md5()));

    FluButton* pSaveAs = addPtn2GridLayout(this, pShowTable, "结果另存为", 4);
    connect(pSaveAs, SIGNAL(clicked()), this, SLOT(slt_saveAs()));
}

void FormBase64Proc::slt_decode()
{
    std::string strText = m_pTextEdit->getDocument().toStdString();
    if(strText.empty())
    {
        showWarningMessage("异常", "未输入可处理数据");
        return;
    }

    if(false == isFileAndRead(strText))
    {
        qDebug() << "slt_decode isFileAndRead failed";
        return;
    }

    const int iSrcDataLen = strText.length();
    m_strLastData.clear();
    m_strLastData = base64_decode(strText);
    const int iDetLen = m_strLastData.length();
    m_pSrcLenInfo.second->setText(QString("%1 字节").arg(iSrcDataLen));
    m_pDetLenInfo.second->setText(QString("%1 字节").arg(iDetLen));
    if (true == m_bMD5Value)
    {
        m_pSrcMD5Info.second->setText(getSrcMD5Value(QString::fromStdString(strText)));
        m_pDetMD5Info.second->setText(getSrcMD5Value(QString::fromStdString(m_strLastData)));
    }
}

void FormBase64Proc::slt_encode()
{
    std::string strText = m_pTextEdit->getDocument().toStdString();
    if(strText.empty())
    {
        showWarningMessage("异常", "未输入可处理数据");
        return;
    }

    if(false == isFileAndRead(strText))
    {
        qDebug() << "slt_encode isFileAndRead failed";
        return;
    }

    const int iSrcDataLen = strText.length();
    m_strLastData.clear();
    m_strLastData = base64_encode(strText.c_str(), strText.length());
    const int iDetLen = m_strLastData.length();
    m_pSrcLenInfo.second->setText(QString("%1 字节").arg(iSrcDataLen));
    m_pDetLenInfo.second->setText(QString("%1 字节").arg(iDetLen));
    if (true == m_bMD5Value)
    {
        m_pSrcMD5Info.second->setText(getSrcMD5Value(QString::fromStdString(strText)));
        m_pDetMD5Info.second->setText(getSrcMD5Value(QString::fromStdString(m_strLastData)));
    }

    m_pTextEdit->setMsgShow(QString::fromStdString(m_strLastData));
}

void FormBase64Proc::slt_md5()
{
    m_bMD5Value = !m_bMD5Value;
    if (true == m_bMD5Value)
    {
        m_pMDValue->setText("MD5已开启");
    }
    else
    {
        m_pMDValue->setText("MD5已关闭");
    }
}

void FormBase64Proc::slt_read()
{
    if(true == m_pTextEdit->showMsg())
    {
        m_pRead->setText("隐藏展示");
    }
    else
    {
        m_pRead->setText("展示结果");
    }
}

void FormBase64Proc::slt_clear()
{
    m_pTextEdit->clear();
    m_pSrcFileType.second->setText("");
    m_pSrcLenInfo.second->setText("");
    m_pSrcMD5Info.second->setText("");
    m_pDetLenInfo.second->setText("");
    m_pDetMD5Info.second->setText("");
    m_pSaveInfo.second->setText("");
    m_pSaveInfo.first->hide();
    m_pSaveInfo.second->hide();
}

void FormBase64Proc::slt_saveAs()
{
    CustomMessageDialog nMessageDialog(nullptr, PROC_TYPE_LINESHOW);
    nMessageDialog.exec();

    m_pSaveInfo.first->show();
    m_pSaveInfo.second->show();
}

void FormBase64Proc::slt_copy2Clipboard()
{
    if(false == hasData())
    {
        showWarningMessage("失败", "数据为空，没有已处理的数据");
        return;
    }

    QApplication::clipboard()->setText(QString::fromStdString(m_strLastData));
}

// 判断是否为文件，对于文件内容则读取文件数据
bool FormBase64Proc::isFileAndRead(std::string &strSrc)
{
    bool bRet = false;

    do
    {
        if(strSrc.empty())
        {
            qDebug() << "isFileAndRead strSrc is empty, len: " << strSrc.length();
            break;
        }

        const std::string strSub = strSrc.substr(0, 8);
        if(strSub == std::string("file:///"))
        {
            // 确认是属于文件路径
            QString strFile = QString::fromStdString(strSrc.substr(8, strSrc.length() - 8));
            if(false == FileExist(strFile))
            {
                showWarningMessage("失败", QString("文件[%1]不存在，请确认!").arg(strFile));
                break;
            }
            else
            {
                // 指定文件存在，则需获取该文件全部内容，以二进制方式读取整个文件，并将数据通过参数返回
                strSrc.clear();
                if(false == ReadFileByBinary(strFile.toStdString(), strSrc))
                {
                    // 读取失败，发出警告
                    showWarningMessage("失败", QString("文件[%1]读取失败，请确认!").arg(strFile));
                    break;
                }
                else
                {
                    //showWarningMessage("成功", QString("文件[%1]读取成功，数据长度: %2 btye").arg(strFile, QString::number(strSrc.length())));
                }

                m_pSrcFileType.second->setText(QString("本地文件"));
            }
        }
        else
        {
            m_pSrcFileType.second->setText(QString("字符数据"));
        }

        bRet = true;
    }while(0);

    return bRet;
}

// 是否存在已编解码结果数据，未有有效结果数据，返回并提示错误
bool FormBase64Proc::hasData()
{
    bool bHasData = !m_strLastData.empty();
    if(false == bHasData)
    {
        //myMessageBoxShowOne(m_eProcType, MSG_SHOW_ERROR, QString("处理结果中未找到有效待保存数据，请先输入内容后执行Base64编解码操作！"));
    }

    return bHasData;
}
